#include <iostream>
#include <dirent.h>
#include <fstream>
#include <regex>

#if defined(_MSC_VER)
#include <direct.h>
#define GetCurrentDir _getcwd
#elif defined(__unix__)
#include <unistd.h>
#define GetCurrentDir getcwd
#else
#endif


std::string getCurrentDir();
void replaceDirContent(const std::string& dirname, const std::string& originalStr, const std::string& targetStr);
void replaceFileContent(const std::string& filename, const std::string& originalStr, const std::string& targetStr);

int main(int argc, char** argv) {
    if(argc < 4)
    {
        std::cout << "Please input [dirname] [original string] and [target string]" << std::endl;
        return -1;
    }

    std::string entry;

    if(argv[1][0] == '/')
    {
        entry = argv[1];
    }
    else
    {
        entry = getCurrentDir() + "/" + argv[1];
    }

    char* entryCStr = const_cast<char *>(entry.c_str());
    replaceDirContent(entryCStr, argv[2], argv[3]);

    return 0;
}

std::string getCurrentDir()
{
    char buff[250];
    GetCurrentDir(buff, 250);
    std::string ret(buff);
    return ret;
}

void replaceDirContent(const std::string& dirname, const std::string& originalStr, const std::string& targetStr)
{
    DIR* dirHandlePtr;
    struct dirent *dirPtr;

    if( (dirHandlePtr = opendir(dirname.c_str())) == nullptr )
    {
        std::cout << "can not open dir : [" << dirname << "]" <<std::endl;
    }

    while((dirPtr = readdir(dirHandlePtr)) != nullptr)
    {
        std::string filename(dirPtr->d_name);
        std::string entry(dirname);
        entry.append("/").append(filename);
        if(filename == "." || filename == "..")
        {
            continue;
        }
        if(dirPtr->d_type == 4)
        {
            replaceDirContent(entry, originalStr, targetStr);
        }
        if(dirPtr->d_type == 8)
        {
            replaceFileContent(entry, originalStr, targetStr);
        }
    }
    closedir(dirHandlePtr);
}

void replaceFileContent(const std::string& filename, const std::string& originalStr, const std::string& targetStr)
{
    std::ifstream inFile(filename, std::ios::in);
    std::string str;
    std::vector<std::string> newFileContent;
    while (std::getline(inFile, str))
    {
        std::regex r(originalStr);
        auto newStr = std::regex_replace(str, r, targetStr);
        newFileContent.push_back(newStr);
    }
    inFile.close();

    std::ofstream outFile(filename, std::ios::out);
    outFile.flush();
    for (auto & i : newFileContent) {
        outFile << i << std::endl;
    }
    outFile.close();
}
